// anonymous 匿名object
function greet(person: {name:string; age: number}) {
    return "Hello " + person.name;
}
// interface
interface Person {
    name: string;
    age: number;
}

function greet1(person:Person) {
    return "Hello " + person.name;
}
// type alias;
type Person1 = {
    name: string;
    age: number;
}

function greet2(person:Person1) {
    return "Hello " + person.name;
}

// function greet1(num:number) {

// }
// 不能方法名相同，传递的参数也相同

//** Property Modifiers */
interface Shape {}
declare function getShape():Shape;

interface PaintOptions {
    shape: Shape;
    xPos?: number;
    yPos?: number;
}

function paintOptions(opts: PaintOptions) {
    // ...
    let xPos = opts.xPos;
    // (property) PaintOptions.yPos?: number | undefined
    let yPos = opts.yPos;
    // let xPos1: number
    let xPos1 = opts.xPos === undefined ? 0 : opts.xPos;

}

function paintOptions1({shape, xPos = 0, yPos = 0}: PaintOptions) {
    console.log("x coordinate at ", xPos);
    // (parameter) yPos: number
    console.log("y coordinate at ", yPos);
}

const shape = getShape();
paintOptions({ shape });
paintOptions({shape, xPos: 100});
paintOptions({shape, xPos: 100, yPos:100});
paintOptions1({shape})


interface SomeType {
    readonly prop:string;
}

function doSomething(obj:SomeType) {
    // We can read from 'obj.pop'.
    console.log(`prop has the value '${obj.prop}'`);
    // Cannot assign to 'prop' because it is a read-only property.
    // obj.prop = "hhhh";
}

interface Home {
    readonly resident: {name:string; age:number};
}

function visitForBirthday(home:Home) {
    // We can read and update properties from 'home.resident'
    console.log(`Happy birthday ${home.resident.name}!`);
    home.resident.age++;
}

function evict(home:Home) {
    // Cannot assign to 'resident' because it is a read-only property
    home.resident = {
        name: "hhhhhh",
        age: 42,
    }
}


interface Person {
    name:string;
    age:number;
}

interface ReadonlyPerson {
    name:string;
    age:number;
}


let writablePerson: Person = {
    name:"Person McPersonface",
    age:42
};

// works
let readonlyPerson:ReadonlyPerson = writablePerson;

console.log(readonlyPerson.age); // 42
writablePerson.age++;
console.log(readonlyPerson.age); // 43

// Index signatures
// 我们知道数据的具体名称，只知道他的类型
interface StringArray {
    [index:number]:string;
}

declare function getStringArray():StringArray;
const myArray:StringArray = getStringArray();
// const myArray: StringArray
const secondItem = myArray[0];
// const secondItem1: any
const secondItem1 = myArray["ttt"];

interface NumberDictionary {
    // 属性名称是字符串
    [index: string]: number | string;
    length: number;
    // Property 'name' of type 'string' is not assignable to 'string' index type
    // 已经有一个string类型的属性名称，不能再有
    name: string;
}
// Excess Property Checks
interface SquareConfig {
    color?:string;
    width?:number;
    [propName:string]:any
}

function createSquare(config: SquareConfig):{color:string; area:number} {
    return {
        color: config.color || "red",
        area: config.width ? config.width * config.width : 20
    };
}

let mySquare = createSquare({colour: "red", color:"red", width:100} as SquareConfig);
let mySquare1 = createSquare({width:100, opaciity:0.5} as SquareConfig);
let mySquare2 = createSquare({width:100, opaciity:0.5});
// extending types
interface BasicAddress {
    name?:string;
    street:string;
    city:string;
    country:string;
    postalCode:string;
}

interface BasicAddressWithUnit {
    name?:string;
    street:string;
    city:string;
    country:string;
    postalCode:string;
}

interface AddressWithUnit extends BasicAddress {
    unit:string;
}

interface Colorful {
    color: string;
}

interface Circle {
    radius:number;
}

interface ColorfulCircle extends Colorful, Circle {}

const cc: ColorfulCircle = {
    color: "red",
    radius: 42,
}

// Intersection Types

type ColorfulCircle1 = Colorful & Circle;


function draw1(circle: Colorful & Circle) {
    console.log(`Color was ${circle.color}` );
    console.log(`Circle was ${circle.radius}` );
}

draw1({color: "blue", radius: 42});
draw1({color: "red", radiiius:43});

// Generic Object Types;
interface Box {
    contents:any;
}

interface Box1 {
    contents:unknown;
}

let x:Box = {
    contents:"Hello world"
};
if (typeof x.contents === "string") {
    console.log(x.contents.toLowerCase());
}

console.log((x.contents as string).toLowerCase());

interface NumberBox {
    contents: number;
}

interface StringBox {
    contents: string;
}

interface BooleanBox {
    contents: boolean;
}


// function setContents(box: StringBox, newContents: string): void;
// function setContents(box: NumberBox, newContents: number): void;
// function setContents(box: BooleanBox, newContents: boolean): void;
// function setContents(box: {centents: any}, newContents: any) {
//     box.centents = newContents
// }
// 关键是还有错

interface Box2<Type> {
    contents:Type;
}

let boxA:Box2<string> = {contents:"hello"};
boxA.contents;

let boxB:StringBox = {contents:"world"};
boxB.contents;

interface Apple {
    ///
}
type AppleBox = Box2<Apple>;


function setContents<Type>(box:Box2<Type>, newContents: Type) {
    box.contents = newContents;
}

type Box3<Type> = {
    contents: Type;
}

type OrNull<Type> = Type | null;

type OneOrMany<Type> = Type | Type[];

type OneOrManyOrNull<Type> = OrNull<OneOrMany<Type>>;

type OneOrManyOrNullStrings = OneOrManyOrNull<String>;

// The Aarry Type
function doSomething1(value:Array<string>) {
    //...
}

let myArray1: string[] = ["hello", "world"];

doSomething1(myArray1);
doSomething1(new Array("hello", "world"));
function doStuff(values:ReadonlyArray<string>) {
    const copy = values.slice;

    console.log(`The first value is ${values[0]}`);

    // ... but we can't mutate 'values'.
    // values.push("hello");
}
// 'ReadonlyArray' only refers to a type, but is being used as a value here.
// new ReadonlyArray("red")

const orArray:ReadonlyArray<string> = ["red", "green", "blue"];

function doStuff1(values:readonly string[]) {
    const copy = values.slice;

    console.log(`The first value is ${values[0]}`);

    // roperty 'push' does not exist on type 'readonly string[]'
    // values.push("hello");
}

let x1:readonly string[] = [];
let y1: string[] = [];

x1 = y1;
// he type 'readonly string[]' is 'readonly' and cannot be assigned to the mutable type 'string[]'.
// y1 = x1;


// Tuple Type
type StringNumberPair = [string, number];

function doSomething2(pair: [string, number]) {
    // const a: string
    const a = pair[0];
    // const b: number
    const b = pair[1];
    // Tuple type '[string, number]' of length '2' has no element at index '2'
    const c = pair[2];
}

doSomething2(["hello", 2]);

function doSomething3(stringHash: [string, number]) {
    const [inputString, hash] = stringHash;
    // const inputString: string
    console.log(inputString);
    // const hash: number
    console.log(hash);
}

interface StringNumberPair1 {
    // specialized properties
    length: 2;
    0:string;
    1:number;
    // other 'Array<string | number>' members...
    slice(start?:number, end?:number):Array<string | number>;
}

type Either2dOr3d = [number, number, number?];
function setCoordinate(coord: Either2dOr3d) {
    // const z: number | undefined
    const [x, y ,z] = coord;
    // (property) length: 2 | 3
    console.log(`Provided coordinates had ${coord.length} dimens`);
}

type StringNumberBooleans = [string, number, ...boolean[]];
type StringBooleansNumber = [string, ...boolean[], number];
type BooleansStringNumber = [...boolean[], string, number];

const a: StringNumberBooleans = ["hello", 1];
const b: StringNumberBooleans = ["beautiful", 2, true];
const c: StringNumberBooleans = ["world", 3, true, false, true];

function readButtonInput(...args:[string, number, ...boolean[]]) {
    const [name, version, ...input] = args;
}

// 等于
function readButtonInput1(name: string, version: number, ...input:boolean[]) {

}

// readonly Tuple Type
function doSomething4(pair: readonly [string, number]) {
    // ...
    pair[0] = "hello";
}

let point = [3, 4] as const;
function distanceFromOrigin([x, y]: [number, number]) {
    return Math.sqrt(x ** 2 + y ** 2);
}
// Argument of type 'readonly [3, 4]' is not assignable to parameter of type '[number, number]'.
// The type 'readonly [3, 4]' is 'readonly' and cannot be assigned to the mutable type '[number, number]'.
distanceFromOrigin(point)
